load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load("@rules_license//rules:license.bzl", "license")

package(default_applicable_licenses = [":license"])

license(
    name = "license",
    license_kinds = ["@rules_license//licenses/spdx:BSD-3-Clause"],
    license_text = "LICENSE",
    visibility = ["//visibility:public"],
)

cc_library(
    name = "fizz",
    srcs = glob(
        ["fizz/**/*.cpp"],
        exclude = [
            "fizz/**/test/*",
            "fizz/extensions/javacrypto/*",
            "fizz/tool/**/*",
        ],
    ),
    hdrs = glob(
        ["fizz/**/*.h"],
        exclude = [
            "fizz/**/test/*",
            "fizz/**/*-inl.h",
            "fizz/extensions/javacrypto/*",
            "fizz/tool/**/*",
        ],
    ) + [":fizz_config_h"],
    copts = select({
        "@platforms//cpu:x86_64": ["-maes"],
        "//conditions:default": [],
    }),
    includes = ["."],
    textual_hdrs = glob(["fizz/**/*-inl.h"]),
    visibility = ["//visibility:public"],
    deps = [
        "@boost.variant",
        "@brotli//:brotlidec",
        "@brotli//:brotlienc",
        "@fmt",
        "@folly//folly:base64",
        "@folly//folly:c_portability",
        "@folly//folly:conv",
        "@folly//folly:exception_wrapper",
        "@folly//folly:executor",
        "@folly//folly:expected",
        "@folly//folly:file",
        "@folly//folly:file_util",
        "@folly//folly:function",
        "@folly//folly:memory",
        "@folly//folly:optional",
        "@folly//folly:overload",
        "@folly//folly:range",
        "@folly//folly:small_vector",
        "@folly//folly:string",
        "@folly//folly:synchronized",
        "@folly//folly/container:evicting_cache_map",
        "@folly//folly/container:f14_hash",
        "@folly//folly/futures:core",
        "@folly//folly/futures:shared_promise",
        "@folly//folly/io:iobuf",
        "@folly//folly/io:socket_option_map",
        "@folly//folly/io/async:async_base",
        "@folly//folly/io/async:async_socket",
        "@folly//folly/io/async:async_transport",
        "@folly//folly/io/async:decorated_async_transport_wrapper",
        "@folly//folly/io/async:delayed_destruction",
        "@folly//folly/io/async:password_in_file",
        "@folly//folly/io/async:ssl_context",
        "@folly//folly/io/async:write_flags",
        "@folly//folly/io/async/ssl:openssl_transport_certificate",
        "@folly//folly/lang:assume",
        "@folly//folly/lang:bits",
        "@folly//folly/lang:checked_math",
        "@folly//folly/net:network_socket",
        "@folly//folly/portability:openssl",
        "@folly//folly/portability:sockets",
        "@folly//folly/portability:unistd",
        "@folly//folly/ssl:openssl_cert_utils",
        "@folly//folly/ssl:openssl_hash",
        "@folly//folly/ssl:openssl_ptr_types",
        "@folly//folly/tracing:static_tracepoint",
        "@glog",
        "@libsodium",
        "@openssl//:ssl",
        "@zlib",
        "@zstd",
    ],
)

# Example CLI app source.
cc_binary(
    name = "tool",
    srcs = glob(
        [
            "fizz/tool/*.cpp",
            "fizz/tool/*.h",
        ],
        exclude = ["fizz/tool/FizzCommandCommon.*"],
    ),
    defines = [
        "FIZZ_TOOL_ENABLE_BROTLI",
        "FIZZ_TOOL_ENABLE_ZSTD",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":fizz_protocol_cert_util",
        ":tool_common_lib",
        "@fizz",
        "@folly//folly:base64",
        "@folly//folly:conv",
        "@folly//folly:file_util",
        "@folly//folly:format",
        "@folly//folly:string",
        "@folly//folly/executors:io_thread_pool_executor",
        "@folly//folly/futures:core",
        "@folly//folly/io:iobuf",
        "@folly//folly/io/async:async_ssl_socket",
        "@folly//folly/io/async:server_socket",
        "@folly//folly/io/async:ssl_context",
        "@folly//folly/io/async/ssl:openssl_transport_certificate",
        "@folly//folly/portability:gflags",
        "@folly//folly/ssl:openssl_cert_utils",
        "@folly//folly/stats:histogram",
        "@glog",
    ],
)

cc_library(
    name = "tool_common_lib",
    srcs = ["fizz/tool/FizzCommandCommon.cpp"],
    hdrs = ["fizz/tool/FizzCommandCommon.h"],
    visibility = ["//visibility:public"],
    deps = [
        ":fizz",
        "@folly//folly:file_util",
        "@folly//folly/io:iobuf",
        "@folly//folly/io/async:async_base",
        "@folly//folly/json:dynamic",
    ],
)

expand_template(
    name = "fizz_config_h",
    out = "fizz/fizz-config.h",
    substitutions = {
        # TODO(kgk): Consider enabling if/when libaegis is added to the BCR.
        "#cmakedefine01 FIZZ_HAVE_LIBAEGIS": "/* #undef FIZZ_HAVE_LIBAEGIS */",
        "#cmakedefine01 FIZZ_CERTIFICATE_USE_OPENSSL_CERT": "#define FIZZ_CERTIFICATE_USE_OPENSSL_CERT 1",
        # TODO(kgk): Consider enabling if/when oqs is added to the BCR.
        "#cmakedefine01 FIZZ_HAVE_OQS": "/* #undef FIZZ_HAVE_OQS */",
        # "FIZZ_HAVE_OQS",
    },
    template = "fizz/fizz-config.h.in",
)

cc_library(
    name = "fizz_protocol_cert_util",
    hdrs = ["fizz/protocol/test/CertUtil.h"],
    includes = ["."],
    visibility = ["//visibility:public"],
    deps = [":fizz"],
)

# ==================================================================================================
# Tests
# ==================================================================================================
EXCLUDED_TEST_SRCS = [
    # Disabled because we don't yet support OQS.
    "fizz/backend/liboqs/test/OQSKeyExchangeTest.cpp",
    # This appears to be some sort of helper binary, not a test or test lib file.
    "fizz/test/BogoShim.cpp",
    # Disabling because this test reliably fails.
    "fizz/experimental/ktls/test/AsyncFizzBaseKTLSTest.cpp",
]

# These files end in Test.cpp but are not tests.
TEST_LIB_SRCS_WITH_TEST_SUFFIX = [
    "fizz/crypto/test/HashTest.cpp",
    "fizz/crypto/test/HmacTest.cpp",
]

# These files are tests, but don't end in Test.cpp.
TEST_SRCS_WITHOUT_TEST_SUFFIX = [
    "fizz/backend/openssl/crypto/signature/test/PeerCertVerify.cpp",
    "fizz/backend/openssl/crypto/test/Hmac.cpp",
    "fizz/record/test/EncryptedRecordBench.cpp",
]

TEST_SRCS = glob(
    ["**/test/*Test.cpp"],
    exclude = EXCLUDED_TEST_SRCS + TEST_LIB_SRCS_WITH_TEST_SUFFIX,
) + TEST_SRCS_WITHOUT_TEST_SUFFIX

TEST_LIB_SRCS = glob(
    ["**/test/*.cpp"],
    exclude = [
        "**/test/*Test.cpp",
        "fizz/test/CMakeTestMain.cpp",
    ] + EXCLUDED_TEST_SRCS + TEST_SRCS_WITHOUT_TEST_SUFFIX,
) + TEST_LIB_SRCS_WITH_TEST_SUFFIX

[cc_test(
    name = test_file.removesuffix(".cpp").replace("/", "_"),
    size = "small",
    srcs = [test_file],
    deps = [
        ":fizz",
        ":fizz_test_lib",
        ":fizz_test_main",
    ],
) for test_file in TEST_SRCS]

# Defines the main function for all unit tests. Use this instead of @googletest//:gtest.
cc_library(
    name = "fizz_test_main",
    srcs = ["fizz/test/CMakeTestMain.cpp"],
    visibility = ["//visibility:public"],
    deps = [
        "@folly//folly/init",
        "@folly//folly/portability:gtest",
    ],
)

# Glob all the sources which are not tests into a single library that all the tests can just use.
cc_library(
    name = "fizz_test_lib",
    srcs = TEST_LIB_SRCS,
    hdrs = glob(["fizz/**/test/*.h"]),
    visibility = ["//visibility:public"],
    deps = [
        ":fizz",
        ":tool_common_lib",
        "@boost.variant",
        "@folly//folly:base64",
        "@folly//folly:benchmark",
        "@folly//folly:exception_wrapper",
        "@folly//folly:file_util",
        "@folly//folly:fixed_string",
        "@folly//folly:format",
        "@folly//folly:function",
        "@folly//folly:memory",
        "@folly//folly:random",
        "@folly//folly:range",
        "@folly//folly:string",
        "@folly//folly/container:array",
        "@folly//folly/executors:manual_executor",
        "@folly//folly/futures:core",
        "@folly//folly/init",
        "@folly//folly/io:iobuf",
        "@folly//folly/io:socket_option_map",
        "@folly//folly/io/async:async_base",
        "@folly//folly/io/async:async_socket",
        "@folly//folly/io/async:async_socket_exception",
        "@folly//folly/io/async:scoped_event_base_thread",
        "@folly//folly/io/async:server_socket",
        "@folly//folly/io/async/test:async_socket_test_lib",
        "@folly//folly/io/async/test:mocks",
        "@folly//folly/json:dynamic",
        "@folly//folly/lang:bits",
        "@folly//folly/portability:gflags",
        "@folly//folly/portability:gmock",
        "@folly//folly/portability:gtest",
        "@folly//folly/ssl:openssl_cert_utils",
        "@folly//folly/ssl:openssl_ptr_types",
        "@folly//folly/test:test_utils",
        "@folly//folly/testing:test_util",
        "@googletest//:gtest",
    ],
)
